home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Archive-tools / DandStoQIF2 / DandStoQIF2.c < prev    next >
C/C++ Source or Header  |  1994-01-21  |  12KB  |  596 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4.  
  5. /*
  6.  * Copyright 1993 by Scott Pendleton
  7.  * Copyright 1994 by David A. Willcox
  8.  *        All rights reserved.
  9.  *
  10.  * This software is provide "as is."  Use at your own risk.
  11.  *
  12.  * This software may be distributed free of charge, as long as this
  13.  * notice is included.  No fee may be charged beyond connection
  14.  * charges for downloading from a bulletin board or on-line service,
  15.  * unless express permission is obtained from the authors.
  16.  */
  17.  
  18. #define MAX_FILENAME    34
  19. #define MAX_LINEWIDTH    512
  20. #define MAXTRANS        20    /* max accts in a transaction */
  21. #define MAXFIELD        11    /* max fields scanned from a line */
  22.  
  23. struct acttrans        /* info about one acct in a transaction */
  24. {
  25.     struct acctalias *ac_cat;        /* alias of category */
  26.     char    ac_dep[20];                /* amt deposited */
  27.     char    ac_with[20];            /* amt withdrawn */
  28.     char    ac_descr[60];            /* a description */
  29. } acttrans[MAXTRANS], actbase;
  30.  
  31. struct acctalias
  32. {
  33.     struct acctalias *aa_link;        /* next alias */
  34.     char    *aa_dnsname;            /* name in input file */
  35.     char    *aa_qifname;            /* name in output file */
  36.     char    *aa_type;                /* type of account */
  37.     int    aa_prio;                    /* "priority" of this acct */
  38. } *Firstalias;
  39.  
  40. char transdate[10];
  41. char cknumber[8];
  42. char payToFrom[60];
  43. char Cleared[5];
  44. char *Fields[MAXFIELD+1];            /* fields scanned from line */
  45. char linebuf[MAX_LINEWIDTH];        /* buffer for input line */
  46. int    smart_map = 1;                    /* 0=>print all, 1=>ignore dups, 2=>prt as comment */
  47. struct acctalias *fundacct = 0;
  48. char outfname[MAX_FILENAME];
  49. FILE *outfptr;
  50. int    doflag = 0;
  51. int postdummy = 0;
  52. int duptrans = 0;
  53.  
  54.  
  55. /* Prototypes */
  56. void    scantran(struct acttrans *ac);
  57. void    dumpit(int nt);
  58. int        isdate(char *str);
  59. void    clrtrans(struct acttrans *);
  60. int        readaliases(char *fname);
  61. struct acctalias    *mapalias (char *name);
  62. struct acctalias *newalias(char *dnsname, char *qifname, char *type, char *prio);
  63. int    getline(FILE *fp);
  64. char    *savestr (char *);
  65. struct acctalias    *isnewacct(char *);
  66.  
  67. main()
  68. {
  69.     FILE *infptr;
  70.     char infname[MAX_FILENAME], Htype[20];
  71.     char c;
  72.     int  count,i;
  73.     int  skipped;
  74.     struct acctalias *newfundacct;
  75.     
  76.     smart_map = -1;
  77.     do
  78.     {
  79.         printf ("Try to suppress duplicate transactions? (y/n): ");
  80.         gets (infname);
  81.         switch (infname[0])
  82.         {
  83.             case 'y':
  84.             case 'Y':
  85.                 smart_map = 1;
  86.                 break;
  87.             case 'n':
  88.             case 'N':
  89.                 smart_map = 0;
  90.                 break;
  91.             case 'c':
  92.             case 'C':
  93.                 smart_map = 2;
  94.                 break;
  95.         }
  96.     } while (smart_map < 0);
  97.     
  98.     if (smart_map > 0)
  99.     {
  100.         postdummy = -1;
  101.         do
  102.         {
  103.             printf ("Post dup transaction to @Dummy if cleared? (y/n): ");
  104.             gets (infname);
  105.             switch (infname[0])
  106.             {
  107.                 case 'y':
  108.                 case 'Y':
  109.                     postdummy = 1;
  110.                     break;
  111.                 case 'n':
  112.                 case 'N':
  113.                     postdummy = 0;
  114.                     break;
  115.             }
  116.         } while (postdummy < 0);
  117.     }
  118.     
  119.     doflag = -1;
  120.     do
  121.     {
  122.         printf ("Include flags in description as <FLG>? (y/n): ");
  123.         gets (infname);
  124.         switch (infname[0])
  125.         {
  126.             case 'y':
  127.             case 'Y':
  128.                 doflag = 1;
  129.                 break;
  130.             case 'n':
  131.             case 'N':
  132.                 doflag = 0;
  133.                 break;
  134.         }
  135.     } while (doflag < 0);
  136.  
  137.     do
  138.     {
  139.         printf ("Name of acct map file (or Return)? ");
  140.         gets (infname);
  141.         if (infname[0] == 0)
  142.             break;
  143.     } while (readaliases(infname) < 0);
  144.     
  145.     for (;;)
  146.     {
  147.         i=0;
  148.         skipped = 0;
  149.         printf("File Name or Return? ");
  150.         gets(infname);
  151.         if (infname[0] == 0)
  152.             break;
  153.         
  154.         infptr = fopen(infname,"r");
  155.         
  156.         if (!infptr)
  157.         {
  158.             printf("\n\nError opening the file: %s\n",infname);
  159.     
  160.             continue;
  161.         }
  162.  
  163.         count = 0;
  164.         while (getline(infptr) >= 0)
  165.         {
  166.             if (isdate(Fields[0]))
  167.             {
  168.                 dumpit(count);
  169.                 count = 0;
  170.                 i=i+1;
  171.                 if ((i % 10) == 0)
  172.                     printf("Number of Transactions Converted: %i\r",i);
  173.  
  174.                 strcpy(transdate,Fields[0]);
  175.                 strcpy(cknumber, Fields[1]);
  176.                 strcpy(payToFrom, Fields[2]);
  177.                 strcpy(Cleared, Fields[6]);
  178.                 scantran(&actbase);
  179.             }
  180.             else if ((newfundacct = isnewacct(Fields[0])) != 0)
  181.             {
  182.                 /* this is start of new funding account */
  183.                 dumpit(count);    /* get rid of old stuff */
  184.                 report (i, skipped);
  185.                 skipped = 0;
  186.  
  187.                 if (outfptr)
  188.                 {
  189.                     fclose (outfptr);
  190.                     outfptr = 0;
  191.                 }
  192.                 fundacct = newfundacct;
  193.                 count = -1;
  194.                 i = 0;
  195.             }
  196.             else
  197.             {
  198.                 if (*Fields[0] != 0    /* header or trailer */
  199.                  || *Fields[3] == 0    /* no category */
  200.                  || count < 0)        /* haven't found start of transaction, yet */
  201.                 {
  202.                     skipped++;
  203.                     continue;
  204.                 }
  205.                 if (count <= MAXTRANS)
  206.                 {
  207.                     scantran(&acttrans[count]);
  208.                     count= count + 1;
  209.                 }
  210.                 else
  211.                 {
  212.                     printf ("Too many transactions\n");
  213.                 }
  214.             }
  215.         }
  216.         dumpit(count);
  217.  
  218.         fclose(infptr);
  219.         if (outfptr)
  220.         {
  221.             fclose(outfptr);
  222.             outfptr = 0;
  223.         }
  224.         report (i, skipped);
  225.         skipped = 0;
  226.         
  227.         printf ("\n");
  228.     }
  229.     printf ("All done.  Please hit RETURN to exit\n\n");
  230.     fgets(linebuf,MAX_LINEWIDTH,infptr);
  231. }
  232.  
  233. report (count, skipped)
  234. {
  235.     char buf[2];
  236.     
  237.     if (fundacct)
  238.     {
  239.         printf ("\n%d Transactions processed for acct %s(%s)\n",
  240.             count, fundacct->aa_dnsname, fundacct->aa_qifname);
  241. #if 0
  242.         if (skipped > 0)
  243.             printf ("   %d garbage lines skipped\n", skipped);
  244. #endif
  245.         if (duptrans)
  246.             printf ("    %d cleared dup transactions\n", duptrans);
  247.         printf ("Press RETURN to contine\n");
  248.         fgets (buf, sizeof buf, stdin);
  249.     }
  250.     duptrans = 0;
  251. }
  252.  
  253. void
  254. dumpit(nt)
  255. int    nt;        /* number of transactions */
  256. {
  257.     register struct acttrans *ap;
  258.     char *comment = "";
  259.     register int acprio;
  260.     int clrchar = 'X';
  261.     
  262.     if (nt <= 0)
  263.         return;
  264.  
  265.     if (smart_map)
  266.     {
  267.         int possdup;
  268.  
  269.         possdup = 0;
  270.  
  271.         acprio = actbase.ac_cat->aa_prio;
  272.         for (ap = &acttrans[nt-1]; ap >= acttrans; --ap)
  273.         {
  274.             if (ap->ac_cat->aa_prio < acprio)
  275.                 continue;
  276.             if (ap->ac_cat->aa_prio == acprio)
  277.             {
  278.                 int cmp;
  279.                 cmp = strcmp (ap->ac_cat->aa_qifname,
  280.                     actbase.ac_cat->aa_qifname);
  281.                 if (cmp < 0)
  282.                     continue;
  283.                 if (cmp == 0)
  284.                 {
  285.                     possdup = 1;
  286.                     continue;
  287.                 }
  288.             }
  289.             comment = "@";
  290.         }
  291.         if (*comment != 0)
  292.         {
  293.             if (postdummy && Cleared[0] != 0)
  294.             {                        /* turn this into posting to "@Dummy" */
  295.                 nt = 1;
  296.                 acttrans[0].ac_cat = mapalias("@Dummy");
  297.                 strcpy(acttrans[0].ac_dep, actbase.ac_dep);
  298.                 strcpy(acttrans[0].ac_with, actbase.ac_with);
  299.                 strcpy(acttrans[0].ac_descr, "Reconciled Transfer");
  300.                 comment = "";
  301.             }
  302.             else if (smart_map == 1)
  303.                 return;                /* Don't print at all */
  304.         }
  305.         else if (possdup)
  306.         {
  307.             printf ("Transaction ");
  308.             if (cknumber[0] != 0)
  309.                 printf("number %s ", cknumber);
  310.             printf ("on date %s might be duplicated\n",
  311.                 transdate);
  312.         }
  313.     }
  314.  
  315.     if (outfptr == 0)
  316.     {
  317.         if (fundacct == 0)
  318.         {
  319.             printf ("ERROR: Transaction with no output file\n");
  320.             return;
  321.         }
  322.         strcpy(outfname,fundacct->aa_qifname);
  323.         strcat(outfname,".QIF");
  324.         outfptr = fopen (outfname, "w");
  325.         if (outfptr == 0)
  326.         {
  327.             printf ("Error opening output file %s\n\n", outfname);
  328.             return;
  329.         }
  330.         if (fundacct->aa_type == 0 || *fundacct->aa_type == 0)
  331.             fundacct->aa_type = "Bank";
  332.         printf ("\nOpening output file %s for acct %s type %s\n", 
  333.             outfname, fundacct->aa_dnsname, fundacct->aa_type);
  334.         fprintf(outfptr,"!Type:%s\n",fundacct->aa_type);
  335.     }
  336.  
  337.     fprintf(outfptr,"%sD%s\n", comment, transdate);
  338.     if (actbase.ac_dep[0] != 0)
  339.         fprintf(outfptr,"%sT%s\n",comment, actbase.ac_dep);
  340.     if (actbase.ac_with[0] != 0)
  341.         fprintf(outfptr,"%sT-%s\n",comment, actbase.ac_with);
  342.     if (Cleared[0] != 0)
  343.         fprintf(outfptr,"%sC%c\n", comment, clrchar);        
  344.     if (cknumber[0] != 0)
  345.         fprintf(outfptr,"%sN%s\n",comment, cknumber);
  346.     fprintf(outfptr,"%sP%s\n",comment, payToFrom);
  347.     if (actbase.ac_descr[0] != 0)
  348.         fprintf(outfptr, "%sM%s\n", comment, actbase.ac_descr);
  349.  
  350.     if (nt <= 1)
  351.     {
  352.         if (actbase.ac_descr[0] || acttrans[0].ac_descr[0])
  353.         {
  354.             if (actbase.ac_descr[0])
  355.             {
  356.                 fprintf (outfptr, "%sM%s", comment, actbase.ac_descr);
  357.                 if (acttrans[0].ac_descr[0])
  358.                     fprintf (outfptr, "; %s\n", acttrans[0].ac_descr);
  359.                 else
  360.                     fprintf (outfptr, "\n");
  361.             }
  362.             else
  363.                 fprintf (outfptr, "%sM%s\n", comment, acttrans[0].ac_descr);
  364.         }
  365.         fprintf (outfptr, "%sL%s\n",
  366.             comment, acttrans[0].ac_cat->aa_qifname);
  367.     }
  368.     else
  369.     {
  370.         if (actbase.ac_descr[0] != 0)
  371.             fprintf(outfptr, "%sM%s\n", comment, actbase.ac_descr);
  372.  
  373.         for (ap = acttrans; ap < &acttrans[nt]; ++ap)
  374.         {
  375.             fprintf (outfptr, "%sS%s\n", comment,
  376.                 ap->ac_cat->aa_qifname);
  377.             if (ap->ac_descr[0])
  378.                 fprintf (outfptr, "%sE%s\n", comment, ap->ac_descr);
  379.  
  380.             if (ap->ac_dep[0])
  381.                 fprintf(outfptr, "%s$-%s\n", 
  382.                     comment, ap->ac_dep);
  383.             if (ap->ac_with[0])
  384.                 fprintf(outfptr, "%s$%s\n", 
  385.                     comment, ap->ac_with);
  386.         }
  387.     }
  388.  
  389.     fprintf(outfptr,"%s^\n", comment);
  390. }
  391.  
  392. /* checks to see if str is a date. Really only checks to see if there are 2 '/' in the */
  393. /* str. very crude! */
  394. int
  395. isdate(str)
  396. register char *str;
  397. {
  398.  
  399.     int count;
  400.     
  401.     count = 0;
  402.     while (*str)
  403.     {
  404.         if (*str == '/')
  405.             count++;
  406.         else if (!isdigit(*str))
  407.             return (0);
  408.         
  409.         ++str;
  410.     }
  411.     if (count != 2)
  412.         return(0);
  413.     return(1);
  414. }
  415.  
  416. /*
  417.  * Clear out a transaction
  418.  */
  419. void
  420. clrtrans(ac)
  421. register struct acttrans *ac;
  422. {
  423.     ac->ac_cat = 0;
  424.     ac->ac_dep[0] = 0;
  425.     ac->ac_with[0] = 0;
  426.     ac->ac_descr[0] = 0;
  427. }
  428.  
  429. /*
  430.  * Scan info about a trans
  431.  */
  432. void
  433. scantran(ac)
  434. register struct acttrans *ac;
  435. {
  436.     ac->ac_cat = mapalias (Fields[3]);
  437.     strcpy(ac->ac_dep, Fields[4]);
  438.     strcpy(ac->ac_with, Fields[5]);
  439.     strcpy(ac->ac_descr, Fields[10]);
  440.     if (doflag && Fields[7][0])
  441.     {
  442.         strcat (ac->ac_descr, "<");
  443.         strcat (ac->ac_descr, Fields[7]);
  444.         strcat (ac->ac_descr, ">");
  445.     }
  446. }
  447.  
  448. /* return permanent copy of a string */
  449. char *
  450. savestr(char *str)
  451. {
  452.     char *ret;
  453.     
  454.     if (str == 0 || *str == 0)
  455.         return ("");
  456.     ret = malloc (strlen (str)+1);
  457.     strcpy (ret, str);
  458.     return (ret);
  459. }
  460.  
  461. struct acctalias *
  462. newalias (register char *dnsname, register char *qifname, char *type, char *priop)
  463. {
  464.     register struct acctalias *ap;
  465.  
  466.     ap = malloc (sizeof *ap);
  467.     ap->aa_link = Firstalias;
  468.     Firstalias = ap;
  469.     ap->aa_qifname = savestr(qifname);
  470.     ap->aa_dnsname = savestr(dnsname);
  471.     ap->aa_type = savestr(type);
  472.     
  473.     if (priop && *priop != 0)
  474.     {
  475.         ap->aa_prio = atoi(priop);
  476.         if (ap->aa_prio < 0)
  477.             ap->aa_prio = 0;
  478.     }
  479.     else if (*qifname == '[')
  480.         ap->aa_prio = 1;
  481.     else
  482.         ap->aa_prio = 0;
  483. #if 0
  484.     printf ("Create alias \"%s\" for \"%s\", prio %d\n",
  485.         ap->aa_qifname, ap->aa_dnsname, ap->aa_prio);
  486. #endif
  487.     return (ap);
  488. }
  489.  
  490. /*
  491.  * read in the alias file
  492.  */
  493. int
  494. readaliases (char *fname)
  495. {
  496.     FILE *afile;
  497.     char dnsname[60];
  498.     char qifname[32];
  499.     struct acctalias *ap;
  500.     
  501.     afile = fopen (fname, "r");
  502.     if (afile == NULL)
  503.         return (-1);
  504.     
  505.     while (getline (afile) >= 0)
  506.     {
  507.         if (*Fields[0] == 0 || *Fields[1] == 0)
  508.             continue;    /* missing field, so skip */
  509.         newalias (Fields[0], Fields[1], Fields[3], Fields[2]);
  510.     }
  511.     fclose (afile);
  512.     return (0);
  513. }
  514.  
  515. /*
  516.  * If input name is found in alias list, replace with its alias
  517.  */
  518. struct acctalias *
  519. mapalias (iname)
  520. register char *iname;
  521. {
  522.     register struct acctalias *ap;
  523.     
  524.     for (ap = Firstalias; ap != 0; ap = ap->aa_link)
  525.     {
  526.         if (ap->aa_dnsname[0] == iname[0]
  527.          && ap->aa_dnsname[1] == iname[1]
  528.          && strcmp (ap->aa_dnsname, iname) == 0)
  529.         {                /* found a match */
  530.             return (ap);
  531.         }
  532.     }
  533.  
  534.     ap = newalias (iname, iname, 0, 0);
  535.     return (ap);
  536. }
  537.  
  538. /*
  539.  * Read an input line and parse it into fields
  540.  * Return number of fields scanned, or -1 for EOF
  541.  */
  542. int
  543. getline(FILE *fp)
  544. {
  545.     register char **tp;    /* pointer to current field */
  546.     register char *lp;    /* latest char in buffer */
  547.  
  548.     if (fgets(linebuf, sizeof linebuf, fp) == NULL)
  549.         return (-1);
  550.     
  551.     for (tp=Fields, lp=linebuf; tp < &Fields[MAXFIELD]; )
  552.     {            /* split line into tab-separated fields */
  553.         *tp++ = lp;    /* record start of field */
  554.  
  555.         while (*lp && *lp != '\t' && *lp != '\n')
  556.             ++lp;    /* find end of field */
  557.  
  558.         if (*lp == 0)
  559.             break;
  560.         *lp++ = 0;    /* null-terminate field */
  561.     }
  562.     while (tp < &Fields[MAXFIELD])
  563.     {
  564.         *tp++ = "";
  565.     }
  566. #if 0
  567.     printf ("getline returns %d: ", tp-Fields);
  568.     {
  569.         int i;
  570.         for (i = 0; i < MAXFIELD; ++i)
  571.         printf (" \"%s\"", Fields[i]);
  572.         printf ("\n");
  573.     }
  574. #endif
  575.     return (tp-Fields);
  576. }
  577.  
  578. /*
  579.  * Check for "Funding account: " line that designates a new funding account
  580.  */
  581. char tag[] = "Funding account: ";
  582. struct acctalias *
  583. isnewacct (char *line)
  584. {
  585.     register char *pl, *pt;
  586.     register struct acctalias *ap;
  587.     
  588.     for (pl = line, pt = tag; *pt; ++pl, ++pt)
  589.     {
  590.         if (*pl != *pt)
  591.             return (0);
  592.     }
  593.     /* The initial tag is correct.  Look up the funding account */
  594.     return (mapalias (pl));
  595. }
  596.